﻿using System;
using System.ComponentModel;
using System.Windows.Controls;
using Notoric.Gui.Windows;

namespace Notoric.Gui.Commands
{
    /// <summary>
    /// Activates the symbol inserter of selected music sections with Common Western Music Notation interior
    /// and instructs it to insert rests.
    /// </summary>
    /// <remarks>
    /// The command expects the basic duration (without augmentation dots) of the inserted rests as its parameter.
    /// If it is not given, the duration is implicitly set to a quarter rest.
    /// </remarks>
    public class InsertRestCommand : RibbonCommand
    {
        #region Constructors

        /// <summary>
        /// Creates a new <see cref="InsertRestCommand"/> instance.
        /// </summary>
        /// <param name="mainWindow">
        /// <para>
        /// Type: <see cref="MainWindow"/>
        /// </para>
        /// <para>
        /// A reference to the main application window.
        /// </para>
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// The <paramref name="mainWindow"/> is <see langword="null"/>.
        /// </exception>
        public InsertRestCommand(MainWindow mainWindow)
            : base(mainWindow)
        {
            mainWindow.DocumentPane.SelectionChanged += new SelectionChangedEventHandler(DocumentPane_SelectionChanged);
        }

        #endregion

        #region ICommand Members

        /// <inheritdoc/>
        public override bool CanExecute(object parameter)
        {
            return (ApplicationWindow.ActivePage != null && ApplicationWindow.ActivePage.SelectedContent == ViewModel.Elements.SelectedContentType.Music)
                || (ApplicationWindow.DocumentPane.SelectedItem is LinearCompositionViewPanel);
        }

        /// <inheritdoc/>
        public override void Execute(object parameter)
        {
            ushort duration;
            if (parameter == null || !ushort.TryParse(parameter.ToString(), out duration))
                duration = 32;

            if (!ApplicationWindow.SymbolInsertionMode_Button.IsChecked)
                ApplicationWindow.SymbolInsertionModeCmd.Execute(true);

            if (ApplicationWindow.AugmentationDot_Button.IsChecked)
                ApplicationWindow.AugmentationDot_Button.IsChecked = false;
            else if (ApplicationWindow.TwoAugmentationDots_Button.IsChecked)
                ApplicationWindow.TwoAugmentationDots_Button.IsChecked = false;
            ApplicationWindow.AugmentationDotsCmd.Execute(null);

            ToggleAccidentalButtonsOff();

            if (ApplicationWindow.DocumentPane.SelectedItem is PagePanel)
            {
                foreach (var section in ApplicationWindow.ActivePage.SelectedSections)
                {
                    if (section.Interior is ViewModel.Elements.CWNotation.MusicSectionInterior)
                    {
                        var symbolInserter = ((ViewModel.Elements.CWNotation.MusicSectionInterior)section.Interior).SymbolInserter;
                        symbolInserter.BasicDuration = duration;
                        symbolInserter.SymbolType = ViewModel.Elements.CWNotation.InsertedSymbolType.Rest;
                    }
                }
            }
            else
            {
                var section = ((ApplicationWindow.DocumentPane.SelectedItem as LinearCompositionViewPanel).DataContext as ViewModel.Elements.LinearCompositionView).Content;
                if (section.Interior is ViewModel.Elements.CWNotation.MusicSectionInterior)
                {
                    var symbolInserter = ((ViewModel.Elements.CWNotation.MusicSectionInterior)section.Interior).SymbolInserter;
                    symbolInserter.BasicDuration = duration;
                    symbolInserter.SymbolType = ViewModel.Elements.CWNotation.InsertedSymbolType.Rest;
                }
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Switches off the accidental toggle buttons.
        /// </summary>
        private void ToggleAccidentalButtonsOff()
        {
            if (ApplicationWindow.AccidentalDoubleFlat_Button.IsChecked)
                ApplicationWindow.AccidentalDoubleFlat_Button.IsChecked = false;
            if (ApplicationWindow.AccidentalFlat_Button.IsChecked)
                ApplicationWindow.AccidentalFlat_Button.IsChecked = false;
            if (ApplicationWindow.AccidentalNeutral_Button.IsChecked)
                ApplicationWindow.AccidentalNeutral_Button.IsChecked = false;
            if (ApplicationWindow.AccidentalDoubleNeutral_Button.IsChecked)
                ApplicationWindow.AccidentalDoubleNeutral_Button.IsChecked = false;
            if (ApplicationWindow.AccidentalSharp_Button.IsChecked)
                ApplicationWindow.AccidentalSharp_Button.IsChecked = false;
            if (ApplicationWindow.AccidentalDoubleSharp_Button.IsChecked)
                ApplicationWindow.AccidentalDoubleSharp_Button.IsChecked = false;
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Occurs when the selected document has changed.
        /// </summary>
        /// <param name="sender">Object where the event handler is attached</param>
        /// <param name="e">Event data</param>
        private void DocumentPane_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (activePage != null)
            {
                activePage.PropertyChanged -= activePage_PropertyChanged;
                activePage = null;
            }

            if (ApplicationWindow.ActivePage != null)
            {
                activePage = ApplicationWindow.ActivePage;
                activePage.PropertyChanged += new PropertyChangedEventHandler(activePage_PropertyChanged);
            }

            RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Occurs when a property of the active page has changed.
        /// </summary>
        /// <param name="sender">Object that has sent the event</param>
        /// <param name="e">Event data</param>
        void activePage_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "SelectedContent")
                RaiseCanExecuteChanged();
        }

        #endregion

        #region Private Fields

        /// <summary>
        /// Holds the active page.
        /// </summary>
        private ViewModel.Elements.Page activePage;

        #endregion
    }
}
